package source;

/*
This file is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License version 2, 1991 as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
details.

A copy of the GNU General Public License can be found at:
http://www.gnu.org/licenses/gpl.html
*/
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import javax.swing.JComponent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import java.util.StringTokenizer;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.event.*;
import javax.swing.table.TableModel;

/*
*<p>Creates the GUI</p>
*/
public class ServerGUI extends JFrame implements ActionListener, ListSelectionListener, TableModelListener  {
	/*
	*<p>The name of the player that the PlayerGUI is attached to</p>
	*/
	public static String playerAttachedTo = "";
	/*
	*<p>The ID of the player that the PlayerGUI is attached to</p>
	*/
	public static int playerAttached=0;
	/*
	*<p>The message printed before each line</p>
	*/
	private final static String serverTag = "[O] ";
	/*
	*<p>The message printed at the end of each line</p>
	*/
	private final static String newLine = "\n";
	/*
	*<p>The text area of the server GUI</p>
	*/
	protected static JTextArea serverConsole;
	/*
	*<p>The scroll for the text area of the server GUI</p>
	*/
	protected static JScrollPane serverConsoleScroll;
	/*
	*<p>The menu of the player GUI</p>
	*/
	protected static JMenuBar playerMenu;
	/*
	*<p>The menu of server GUI</p>
	*/
	protected static JMenu menu;
	/*
	*<p>The buttons that perform actions in the server menu</p>
	*/
	protected static JMenuItem bootall, shutdown,update;
	/*
	*<p>A button that performs a server yell</p>
	*/
	protected static JButton yell;
	/*
	*<p>The frame that holds the list of players</p>
	*/
	protected static JPanel userListPanel;
	/*
	*<p>Controls for the list of players</p>
	*/
	protected static JPanel userListPanelControls;
	/*
	*<p>The console for the playerGUI</p>
	*/
	protected static JTextArea playerConsole;
	/*
	*<p>The scroll for the player GUI console</p>
	*/
	protected static JScrollPane playerConsoleScroll;
	/*
	*<p>The list of players online</p>
	*/
	protected static JList playerUsers;
	/*
	*<p>The scroll for the list of players</p>
	*/
	protected static JScrollPane playerUsersScroll;
	/*
	*<p>The menu bar for server GUI</p>
	*/
	protected static JMenuBar serverMenu;
	/*
	*<p>A menu for the server GUI</p>
	*/
	protected static JMenu cmd;
	/*
	*<p>The things in the menu for the server GUI</p>
	*/
	protected static JMenuItem mod, tele, ban, ipban, item, kick;
	/*
	*<p>A button that attached the player GUI to the selected player</p>
	*/
	protected static JButton Attach;
	/*
	*<p>A button that allows the server GUI to message the player attached to</p>
	*/
	protected static JButton Message;
	/*
	*<p>The last selection of the list</p>
	*/
	private static Object lastSelection;
	/*
	*<p>The users on the player list</p>
	*/
	public static String users[] = new String[PlayerHandler.maxPlayers];
	/*
	*<p>A tab that allows people to click on it</p>
	*/
	protected static JTabbedPane tab;
	/*
	*<p>Frame to hold things</p>
	*/
	protected static JPanel playerGUI, serverGUI, npcList;
	/*
	*<p>The scroll for the NPC table</p>
	*/
	protected static JScrollPane npcListScroll;
	/*
	*<p>The NPC Table that is editable</p>
	*/
	protected static JTable npcListTable;
	/*
	*<p>The menu for the NPC Table</p>
	*/
	protected static JMenuBar npcListMenu;
	/*
	*<p>A button that saves the edited files to config/npcs.cfg</p>
	*/
	protected static JButton saveList;
	/**
	*<p>Sets up the GUI</p>
	*/
	public ServerGUI() {
		setDefaultLookAndFeelDecorated(true);
		setPreferredSize(new Dimension(500, 300));
		initComponents();
		for (int i = 0; i < PlayerHandler.maxPlayers; i++){
			users[i] = "";
		}
		setResizable(false);
		setTitle("OpenedScape Server GUI");
	}
	/**
	*<p>Sets the GUI to be visible</p>
	*/
	public static void main(){
		new ServerGUI().setVisible(true);
	}
	/**
	*<p>Adds consoleText to the player console if consoleTag is true</p>
	*@param consoleText String
	*@param consoleTag boolean
	*/
	public static void addConsole(String consoleText, boolean consoleTag) {
		if (consoleTag)
			playerConsole.append(serverTag + consoleText + newLine);
	}
	/**
	*<p>Adds consoleText to the server console if consoleTag is true</p>
	*@param consoleText String
	*@param consoleTag boolean
	*/
	public static void addSConsole(String consoleText, boolean consoleTag) {
		if (consoleTag)
			serverConsole.append(serverTag + consoleText + newLine);
	}
	/**
	*<p>Updates the player list</p>
	*/
	public static void process() {
		String[] players = PlayerHandler.playersCurrentlyOn;
		int len = 0;
		for (int i = 0; i < players.length; i++) {
			if (players[i] != null)
				len++;
		}
		boolean Do = false;
		for (int i = 0; i < players.length; i++){
			if (players[i] != null){
				if (users[i].startsWith(players[i])){
					Do = true;
				}
			}
		}
		if (Do){
			users = new String[len];
			int pos = 0;
			for (int i = 0; i < players.length; i++) {
				if (players[i] != null)
					users[pos++] = players[i];
			}
			playerUsers.setListData(users);
		}
	}
	/**
	*<p>Creates the GUI</p>
	*/
	private void initComponents() {
		playerConsoleScroll = new JScrollPane();
		playerConsole = new JTextArea();
		playerUsersScroll = new JScrollPane();
		playerUsers = new JList();
		userListPanel = new JPanel(new BorderLayout());
		userListPanelControls = new JPanel(new BorderLayout());
		serverConsoleScroll = new JScrollPane();
		serverConsole = new JTextArea();
		playerMenu = new JMenuBar();
		Attach = new JButton("Attach");
		Message = new JButton("Message");
		cmd = new JMenu("Commands");
		mod = new JMenuItem("Mod");
		tele = new JMenuItem("Teleport");
		ban = new JMenuItem("Ban");
		ipban = new JMenuItem("IP Ban");
		item = new JMenuItem("Spawn Item");
		kick = new JMenuItem("Kick");
		tab = new JTabbedPane();
		yell = new JButton("Yell");
		serverMenu = new JMenuBar();
		menu = new JMenu("Maintainance");
		bootall = new JMenuItem("Bootall");
		shutdown = new JMenuItem("Shutdown");
		update = new JMenuItem("Update");
		saveList = new JButton("Save");
		playerGUI = new JPanel(new BorderLayout());
		serverGUI = new JPanel(new BorderLayout());
		npcList = new JPanel(new BorderLayout());
		npcListMenu = new JMenuBar();
		npcListGUI npcListModel = new npcListGUI();
		for (int i = 0; i < NPCList.maxListedNPCs && NPCList.npcName[i] != null; i++){
			npcListModel.data[i][0] = i;
			npcListModel.data[i][1] = NPCList.npcName[i];
			npcListModel.data[i][2] = NPCList.npcCombat[i];
			npcListModel.data[i][3] = NPCList.npcHealth[i];
		}
		npcListTable = new JTable(npcListModel);
		npcListTable.getModel().addTableModelListener(this);
		npcListScroll = new JScrollPane(npcListTable);


		playerUsers.setToolTipText("List of players on the server.");
		cmd.setToolTipText("Commands that affect the player.");
		Attach.setToolTipText("Attachs the control panel to the selected player.");
		Message.setToolTipText("Sends a message that the attached player hears.");
		mod.setToolTipText("Changes the rights the player has.");
		tele.setToolTipText("Teleports a player to the designated X and Y coordinate.");
		ban.setToolTipText("Stops the account from being played on this server.");
		ipban.setToolTipText("Stops the player from playing on this server.");
		item.setToolTipText("Spawns an item in the attached player's inventory.");
		kick.setToolTipText("Disconnects the attached player from the server.");
		yell.setToolTipText("Sends a message that everyone on the server hears.");
		menu.setToolTipText("Commands that can be executed.");
		bootall.setToolTipText("Everyone is disconnected from the server.");
		shutdown.setToolTipText("Stops all connections to server, and closes port.(Does not save games)");
		update.setToolTipText("Sets the time before everyone is disconnected from the server.");

		cmd.add(mod);
		cmd.add(tele);
		cmd.add(item);
		cmd.add(kick);
		cmd.add(ban);
		cmd.add(ipban);

		menu.add(bootall);
		menu.add(shutdown);
		menu.add(update);

		saveList.setActionCommand("savelist");

		saveList.addActionListener(this);
		
		npcListMenu.add(saveList);

		Attach.addActionListener(this);
		Message.addActionListener(this);
		bootall.addActionListener(this);
		shutdown.addActionListener(this);
		update.addActionListener(this);
		yell.addActionListener(this);
		mod.addActionListener(this);
		tele.addActionListener(this);
		item.addActionListener(this);
		item.setActionCommand("item");
		ban.addActionListener(this);
		ipban.addActionListener(this);
		kick.addActionListener(this);

		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setFont(new Font("Arial", 1, 10));

		serverConsole.setEditable(false);
		serverConsole.setFont(new Font("Tahoma", 0, 12));
		serverConsole.setRows(9);
		serverConsole.setBorder(new EtchedBorder(null, new Color(102, 102, 102)));

		serverConsoleScroll.setViewportView(serverConsole);
		serverConsoleScroll.setAutoscrolls(true);

		playerConsole.setEditable(false);
		playerConsole.setFont(new Font("Tahoma", 0, 12));
		playerConsole.setRows(9);
		playerConsole.setBorder(new EtchedBorder(null, new Color(102, 102, 102)));

		playerConsoleScroll.setAutoscrolls(true);
		playerConsoleScroll.setViewportView(playerConsole);

		playerUsers.setBorder(new EtchedBorder(null, new Color(102, 102, 102)));
		playerUsers.setPreferredSize(new Dimension(80, 100));
		playerUsers.setListData(new String[]{"12-letters:)"});
		playerUsers.addListSelectionListener(this);

		playerUsersScroll.setViewportView(playerUsers);
		playerUsersScroll.setAutoscrolls(true);

		userListPanelControls.add(Attach, BorderLayout.SOUTH);

		userListPanel.add(playerUsersScroll);
		userListPanel.add(userListPanelControls, BorderLayout.SOUTH);

		playerGUI.add(playerConsoleScroll);
		playerGUI.add(userListPanel, BorderLayout.EAST);
		playerGUI.add(playerMenu, BorderLayout.NORTH);

		playerMenu.add(cmd);
		playerMenu.add(Message);

		serverMenu.add(menu);
		serverMenu.add(yell);

		npcList.add(npcListMenu, BorderLayout.NORTH);
		npcList.add(npcListScroll);

		serverGUI.add(serverConsoleScroll);
		serverGUI.add(serverMenu, BorderLayout.NORTH);

		tab.addTab("Server", serverGUI);
		tab.addTab("Player", playerGUI);
		tab.addTab("NPC List", npcList);
		getContentPane().add(tab);
		pack();
	}
	/**
	*<p>Handles a changed value in the table</p>
	*@param e TableModelEvent
	*/
	public void tableChanged(TableModelEvent e) {
		int row = e.getFirstRow();
		int column = e.getColumn();
		TableModel model = (TableModel)e.getSource();
		String columnName = model.getColumnName(column);
		Object data = model.getValueAt(row, column);
		if (column == 1){
			NPCList.npcName[row] = data.toString();
		}else if (column == 2){
			NPCList.npcCombat[row] = Integer.parseInt(""+data);
		}else if (column == 3){
			int temp = NPCList.npcHealth[row] - Integer.parseInt(""+data);
			NPCList.npcHealth[row] = Integer.parseInt(""+data);
			for (int i = 0; i < NPCHandler.maxNPCs; i++){
				if (NPCHandler.npcs[i] != null){
					if (NPCHandler.npcs[i].npcType == row){
						NPCHandler.npcs[i].HP += temp;
						NPCHandler.npcs[i].MaxHP += temp;
					}
				}
			}
		}
	}
	/**
	*<p>Handles a changed value in the list</p>
	*@param evt ListSelectionEvent
	*/
	public void valueChanged(ListSelectionEvent evt) {
		if (playerUsers.getSelectedValue() != null && !playerUsers.getSelectedValue().equals("")) {
			lastSelection = playerUsers.getSelectedValue();
		}
	}
	/**
	*<p>Returns the PlayerGUI is attached to a player</p>
	*@return boolean
	*/
	public static boolean checkAttachedTo(){
		if (playerAttachedTo.equals("")){
			return false;
		}
		for (int i = 0; i<PlayerHandler.maxPlayers; i++){
			if (PlayerHandler.players[i]!= null && PlayerHandler.players[i].playerName.equalsIgnoreCase(playerAttachedTo)){
				return true;
			}
		}
		return false;
	}
	/**
	*<p>Handles an action event</p>
	*@param evt ActionEvent
	*/
	public void actionPerformed(ActionEvent evt) {
		String gsc = evt.getActionCommand();
		gsc = gsc.toLowerCase();
		boolean used = true;
		if (gsc.trim().equals("")){
			return;
		}
		if (gsc.equals("savelist")){
			NPCList.saveList();
		}
		if (gsc.equals("ban")) {
			if (checkAttachedTo()) {
				PlayerHandler.BanNick = playerAttachedTo;
				addConsole(lastSelection + " banned", true);
				misc.println(lastSelection + " banned");
			} else{
				JOptionPane.showMessageDialog(null, "No player is selected", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		} else if (gsc.equals("ipban") || gsc.equals("ip ban")) {
			if (checkAttachedTo()) {
				PlayerHandler.IPBanNick = playerAttachedTo;
				addConsole(lastSelection + " IP banned", true);
				misc.println(lastSelection + " IP banned");
			} else{
				JOptionPane.showMessageDialog(null, "No player is selected", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else if (gsc.equals("attach")){
			if (lastSelection != null) {
				playerAttachedTo = ((String) lastSelection);
				addConsole("Attached To:"+((String) lastSelection), true);
			} else{
				JOptionPane.showMessageDialog(null, "No player to attach to", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else if (gsc.equals("kick") && evt.getSource() == kick){
			if (checkAttachedTo()) {
				PlayerHandler.kickNick = playerAttachedTo;
				addConsole(lastSelection + " kicked", true);
				misc.println(lastSelection + " kicked");
			} else{
				JOptionPane.showMessageDialog(null, "No player is selected", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else if (gsc.startsWith("msg") || gsc.startsWith("message")){
			if (checkAttachedTo()) {
				for (int i = 0; i<PlayerHandler.maxPlayers; i++){
					client p = (client)PlayerHandler.players[i];
					if (p!= null && p.playerName.equalsIgnoreCase(playerAttachedTo)){
						String msg = JOptionPane.showInputDialog(null, "Please type the message:", "Private Message", JOptionPane.QUESTION_MESSAGE);
						if (msg!= null && msg != ""){
							p.sendMessage("[CONSOLE]: "+msg);
							addConsole("[CONSOLE]: "+msg, true);
						}
					}
				}
			} else {
				JOptionPane.showMessageDialog(null, "No player is selected", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else if (gsc.startsWith("item")){
			if (checkAttachedTo()) {
				for (int i = 0; i<PlayerHandler.maxPlayers; i++){
					client p = (client)PlayerHandler.players[i];
					if (p!= null && p.playerName.equalsIgnoreCase(playerAttachedTo)){
						try{
							int itemid = Integer.parseInt(JOptionPane.showInputDialog(null, "Please type the item ID to spawn in "+p.playerName+"'s inventory:", "Spawn Item", JOptionPane.QUESTION_MESSAGE));
							int amt = 1;
							if (Item.itemStackable[itemid]){
								amt = Integer.parseInt(JOptionPane.showInputDialog(null, "Please type the amount of items to spawn in "+p.playerName+"'s inventory:", "Spawn Item", JOptionPane.QUESTION_MESSAGE));
							}
							p.addItem(itemid, amt);
						}catch (Exception e){
							JOptionPane.showMessageDialog(null, "Synatax Error", "Command Error", JOptionPane.ERROR_MESSAGE);
						}
					}
				}
			} else {
				JOptionPane.showMessageDialog(null, "No player is selected", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else if (gsc.startsWith("tele")){
			if (checkAttachedTo()) {
				for (int i = 0; i<PlayerHandler.maxPlayers; i++){
					client p = (client)PlayerHandler.players[i];
					if (p!= null && p.playerName.equalsIgnoreCase(playerAttachedTo)){
						try{
							p.teleportToX = Integer.parseInt(JOptionPane.showInputDialog(null, "Please type the X Position to teleport "+p.playerName+" to:", "Teleport", JOptionPane.QUESTION_MESSAGE));
							p.teleportToY = Integer.parseInt(JOptionPane.showInputDialog(null, "Please type the Y Position to teleport "+p.playerName+" to:", "Teleport", JOptionPane.QUESTION_MESSAGE));
						}catch (Exception e){
							used = false;
						}
					}
				}
			} else {
				JOptionPane.showMessageDialog(null, "No player is selected", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else if (gsc.startsWith("mod")){
			if (checkAttachedTo()) {
				for (int i = 0; i<PlayerHandler.maxPlayers; i++){
					client p = (client)PlayerHandler.players[i];
					if (p!= null && p.playerName.equalsIgnoreCase(playerAttachedTo)){
						try{
							int mod = Integer.parseInt(JOptionPane.showInputDialog(null, "Please type the rights for the player:", "Mod", JOptionPane.QUESTION_MESSAGE));
							p.playerRights = mod;
							misc.println(p.playerName+" is now player right level "+mod);
						}catch (Exception e){
							used = false;
						}
					}
				}
			} else {
				JOptionPane.showMessageDialog(null, "No player is selected", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else if (gsc.equals("kickall") || gsc.equals("bootall")){
			PlayerHandler.kickAllPlayers = true;
			misc.println("Everyone kicked");
		}else if (gsc.startsWith("kick")){
			String kick = JOptionPane.showInputDialog(null, "Who do you wish to kick master?", "Kick", JOptionPane.QUESTION_MESSAGE);
			if (kick != null && kick != ""){
				PlayerHandler.kickNick = kick;
				misc.println(kick + " kicked");
			}
		}else if (gsc.equals("shutdown")){
			PlayerHandler.updateSeconds = 1;
			PlayerHandler.updateAnnounced = false;
			PlayerHandler.updateRunning = true;
			PlayerHandler.updateStartTime = System.currentTimeMillis();
			server.shutdownServer = true;
			misc.println("Server shutting down");
		}else if (gsc.startsWith("yell") || gsc.startsWith("msg")){
			String yell = JOptionPane.showInputDialog(null, "Please type the message to yell:", "Yell", JOptionPane.QUESTION_MESSAGE);
			if (yell != null && yell != ""){
				PlayerHandler.messageToAll = "[CONSOLE]: "+yell;
				misc.println("[CONSOLE]: "+yell);
			}
		}else if (gsc.startsWith("update")){
			try{
				PlayerHandler.updateSeconds = (Integer.parseInt(JOptionPane.showInputDialog(null, "Please type the number of seconds before the update:", "Update", JOptionPane.QUESTION_MESSAGE)) + 1);
				if (PlayerHandler.updateSeconds == 0){
					return;
				}
				PlayerHandler.updateAnnounced = false;
				PlayerHandler.updateRunning = true;
				PlayerHandler.updateStartTime = System.currentTimeMillis();
			}catch (Exception e){
				JOptionPane.showMessageDialog(null, "Unknown Command: "+ gsc.split(" ")[0]+ ", or syntax error", "Command Error", JOptionPane.ERROR_MESSAGE);
			}
		}else{
			used = false;
		}
		if (!used){
			JOptionPane.showMessageDialog(null, "Unknown Command: "+ gsc.split(" ")[0]+ ", or syntax error", "Command Error", JOptionPane.ERROR_MESSAGE);
		}
	}
	/**
	*<p>Creates the TableModel for the NPCList Table</p>
	*/
	private class npcListGUI extends AbstractTableModel {
		/**
		*<p>Creates the names of the columns of the table</p>
		*/
		String[] columnNames = {"ID","Name","Combat Level","Health"};
		/**
		*<p>Creates the slots for the rows of the table</p>
		*/
		Object data[][] = new Object[NPCList.maxListedNPCs][4];
		/**
		*<p>Gets the amount of columns there are</p>
		*@return int
		*/
		public int getColumnCount() {
			return columnNames.length;
		}
		/**
		*<p>Gets the amount of rows there are</p>
		*@return int
		*/
		public int getRowCount() {
			return data.length;
		}
		/**
		*<p>Gets the name of the column at col</p>
		*@param col int
		*@return int
		*/
		public String getColumnName(int col) {
			return columnNames[col];
		}
		/**
		*<p>Gets the value at row and col</p>
		*@param row int
		*@param col int
		*@return Object
		*/
		public Object getValueAt(int row, int col) {
			return data[row][col];
		}
		/**
		*<p>Gets the Class at column c</p>
		*@param c int
		*@return Class
		*/
		public Class getColumnClass(int c) {
			return getValueAt(0, c).getClass();
		}
		/**
		*<p>Returns whether or not the cell at row, col is editable</p>
		*@param row int
		*@param col int
		*@return boolean
		*/
		public boolean isCellEditable(int row, int col) {
			return true;
		}
		/**
		*<p>Sets the value at row, col to be vaule</p>
		*@param row int
		*@param col int
		*@param value Object
		*/
		public void setValueAt(Object value, int row, int col) {
			data[row][col] = value;
			fireTableCellUpdated(row, col);
		}
	}
}
